﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace BU
{
    [Serializable()]
    class Rek
    {
        private Point[] hoeken;

        private Zijde[] zijden;

        /// <summary>
        /// Dit zijn de coefficienten van een specifiek punt
        /// </summary>
        private double coefficient1; // dit is de hoogste waarde
        private double coefficient2; // dit is de laagste waarde


        /// <summary>
        /// Dit zijn de coefficienten van het andere punt
        /// </summary>
        private double coefficient3; // dit is de hoogste waarde
        private double coefficient4; // dit is de laagste waarde

        // In het geval dat meerdere X of Y waarden aan elkaar gelijk zijn dan moet deze True worden
        private bool perfecteRechthoek;

        public Rek(Point hoek1, Point hoek2, Point hoek3, Point hoek4)
        {
            hoeken = new Point[4];
            hoeken[0] = hoek1;
            hoeken[1] = hoek2;
            hoeken[2] = hoek3;
            hoeken[3] = hoek4;
            perfecteRechthoek = checker(hoeken);
            if (!perfecteRechthoek) { Orden(); }
            BerekenCoefficienten();
        }

        private void Orden()
        {
            Point[] temp = new Point[4];
            // De rechter wordt bepaald
            int t1 = Math.Min(hoeken[0].X, hoeken[1].X);
            int t2 = Math.Min(hoeken[2].X, hoeken[3].X);
            int tr = Math.Min(t2, t1);
            
            // De bovenste wordt bepaald
            t1 = Math.Min(hoeken[0].Y, hoeken[1].Y);
            t2 = Math.Min(hoeken[2].Y, hoeken[3].Y);
            int tb = Math.Min(t2, t1);
            // De linker wordt bepaald
            t1 = Math.Max(hoeken[0].X, hoeken[1].X);
            t2 = Math.Max(hoeken[2].X, hoeken[3].X);
            int tl = Math.Max(t2, t1);
            // De onderste wordt bepaald
            t1 = Math.Max(hoeken[0].Y, hoeken[1].Y);
            t2 = Math.Max(hoeken[2].Y, hoeken[3].Y);
            int to = Math.Max(t2, t1);
            //alle punten worden doorlopen
            for (int i = 0; i < 4; i++)
            {
                if (tr == hoeken[i].X) { temp[0] = hoeken[i]; }
                if (tb == hoeken[i].Y) { temp[1] = hoeken[i]; }
                if (tl == hoeken[i].X) { temp[2] = hoeken[i]; }
                if (to == hoeken[i].Y) { temp[3] = hoeken[i]; }
            }
        }

        public Rek(List<Point> lijst)
        {
            hoeken = new Point[4];
            hoeken[0] = lijst[0];
            hoeken[1] = lijst[1];
            hoeken[2] = lijst[2];
            hoeken[3] = lijst[3];
            perfecteRechthoek = checker(hoeken);
            BerekenCoefficienten();
        }

        /// <summary>
        /// Handelt de Singleton af met een image
        /// </summary>
        /// <param name="Plattegrond">Image van plattegrond</param>
        /// <returns></returns>
        public Rek(SerializationInfo info, StreamingContext ctxt)
        {
            this.hoeken = (Point[])info.GetValue("Hoeken", typeof(Point[]));
            this.zijden = (Zijde[])info.GetValue("Zijden", typeof(Zijde[]));
            this.coefficient1 = (double)info.GetValue("Coefficient1", typeof(double));
            this.coefficient2 = (double)info.GetValue("Coefficient2", typeof(double));
            this.coefficient3 = (double)info.GetValue("Coefficient3", typeof(double));
            this.coefficient4 = (double)info.GetValue("Coefficient4", typeof(double));
            this.perfecteRechthoek = (bool)info.GetValue("PerfecteRechthoek", typeof(bool));
        }

        /// <summary>
        /// Methode voor de fields toe te voegen aan het serializen
        /// </summary>
        /// <param name="info"></param>
        /// <param name="ctxt"></param>
        public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            info.AddValue("Hoeken", this.hoeken);
            info.AddValue("Zijden", this.zijden);
            info.AddValue("Cofficient1", this.coefficient1);
            info.AddValue("Cofficient2", this.coefficient2);
            info.AddValue("Cofficient3", this.coefficient3);
            info.AddValue("Cofficient4", this.coefficient4);
            info.AddValue("PerfecteRechthoek", this.perfecteRechthoek);
        }

        private bool checker(Point[] hoeken)
        {
            return (hoeken[0].X == hoeken[1].X || hoeken[1].X == hoeken[2].X || hoeken[2].X == hoeken[3].X || hoeken[0].X == hoeken[2].X || hoeken[0].X == hoeken[3].X || hoeken[1].X == hoeken[3].X || hoeken[0].Y == hoeken[1].Y || hoeken[1].Y == hoeken[2].Y || hoeken[2].Y == hoeken[3].Y || hoeken[0].Y == hoeken[2].Y || hoeken[0].Y == hoeken[3].Y || hoeken[1].Y == hoeken[3].Y);
        }

        public Rek(Point[] hoeken)
        {
            this.hoeken = hoeken;
            perfecteRechthoek = checker(hoeken);
            BerekenCoefficienten();
        }

        private void BerekenCoefficienten()
        {
            if (!perfecteRechthoek)
            {
                //het y verschil
                double overstaande = hoeken[0].Y - hoeken[1].Y;
                //het x verschil
                double aanliggende = hoeken[1].X - hoeken[0].X;
                coefficient1 = Math.Atan(overstaande / aanliggende);

                overstaande = hoeken[3].Y - hoeken[0].Y;
                aanliggende = hoeken[3].X - hoeken[0].X;
                coefficient2 = Math.Atan(overstaande / aanliggende);

                overstaande = hoeken[2].Y - hoeken[1].Y;
                aanliggende = hoeken[2].X - hoeken[1].X;
                coefficient3 = Math.Atan(overstaande / aanliggende);

                overstaande = hoeken[3].Y - hoeken[2].Y;
                aanliggende = hoeken[2].X - hoeken[3].X;
                coefficient4 = Math.Atan(overstaande / aanliggende);
            }
        }

        public bool binnenRek(Point plaats)
        {
            if (perfecteRechthoek)
            {
                return EvenRek(plaats);
            }
            else
            {
                return OnEvenRek(plaats);
            }
        }

        private bool OnEvenRek(Point plaats)
        {
            double overstaande;
            double aanliggende;
            bool boven1;
            if (plaats.X == hoeken[0].X || plaats.Y == hoeken[0].Y) { }
            if (plaats.X == hoeken[0].X && plaats.Y == hoeken[0].Y || (plaats.X == hoeken[2].Y) && (plaats.Y == hoeken[2].Y)) { return true; }
            if (plaats.Y < hoeken[0].Y)
            {
                overstaande = hoeken[0].Y - plaats.Y;
                boven1 = true;
            }
            else
            {
                overstaande = plaats.Y - hoeken[0].Y;
                boven1 = false;
            }
            if (plaats.X > hoeken[0].X)
            {
                aanliggende = plaats.X- hoeken[0].X;
                double temp = Math.Atan(overstaande / aanliggende);
                if (boven1) 
                {
                    if (temp > coefficient1) { return false; }
                }
                else 
                {
                    if (temp > coefficient2) { return false; }
                }
            }
            else
            {
                return false;
            }

            if (plaats.X == hoeken[2].X || plaats.Y == hoeken[2].Y) { }
            if (plaats.Y < hoeken[2].Y)
            {
                overstaande = hoeken[2].Y - plaats.Y;
                boven1 = true;
            }
            else
            {
                overstaande = plaats.Y - hoeken[2].Y;
                boven1 = false;
            }
            if (plaats.X < hoeken[2].X)
            {
                aanliggende = hoeken[2].X - plaats.X;
                double temp = Math.Atan(overstaande / aanliggende);
                if (boven1)
                {
                    if (temp > coefficient1) { return false; }
                }
                else
                {
                    if (temp > coefficient2) { return false; }
                }
            }
            else
            {
                return false;
            }
            return true;
        }

        public bool EvenRek(Point plaats)
        {
            return false;
        }

        #region properties
        internal Point[] Hoeken
        {
            get { return hoeken; }
            set { hoeken = value; }
        }

        internal Zijde[] Zijden
        {
            get { return zijden; }
            set { zijden = value; }
        }

        public double Coefficient1
        {
            get { return coefficient1; }
            set { coefficient1 = value; }
        }

        public double Coefficient2
        {
            get { return coefficient2; }
            set { coefficient2 = value; }
        }

        public double Coefficient3
        {
            get { return coefficient3; }
            set { coefficient3 = value; }
        }

        public double Coefficient4
        {
            get { return coefficient4; }
            set { coefficient4 = value; }
        }

        public bool PerfecteRechthoek
        {
            get { return perfecteRechthoek; }
            set { perfecteRechthoek = value; }
        }
        #endregion

    }

    /// <summary>
    /// Composiet relatie tussen BURek en BUZijde
    /// </summary>
    class Zijde
    {
        Point een;
        Point twee;
        private Point x; //De x locatie in het rek        
        private Point y; //De y locatie in het rek        
        private List<BUSchap> schappen; //De lijst van schappen in het rek        

        /// <summary>
        /// Een zijde van een rek (constructor)
        /// </summary>
        /// <param name="een">Een van de twee punten waartussen de zijde zit</param>
        /// <param name="twee">Een van de twee punten waartussen de zijde zit</param>
        public Zijde(Point een, Point twee)
        {
            this.een = een;
            this.twee = twee;
        }

        public Zijde(SerializationInfo info, StreamingContext ctxt)
        {
            this.een = (Point)info.GetValue("Een", typeof(Point));
            this.twee = (Point)info.GetValue("Twee", typeof(Point));
            this.x = (Point)info.GetValue("X", typeof(Point));
            this.y = (Point)info.GetValue("Y", typeof(Point));
        }

        public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            info.AddValue("Een", this.een);
            info.AddValue("Twee", this.twee);
            info.AddValue("X", this.x);
            info.AddValue("Y", this.y);
        }

        /// <summary>
        /// Voegt een schap toe aan het rek
        /// </summary>
        /// <param name="schap">Het toe te voegen schap</param>
        public void VoegSchapToe(BUSchap schap)
        {
            this.schappen.Add(schap);
        }

        /// <summary>
        /// Verwijdert een schap uit het rek
        /// </summary>
        /// <param name="schap">Het te verwijderen schap</param>
        public void VerwijderSchap(BUSchap schap)
        {
            this.schappen.Remove(schap);
        }

    }
}
